package model;

import java.util.Random;

public class WeightedWheelSelectionStrategy implements OrganismSelectionStrategy
{
	
	Random randomGenerator = new Random(System.currentTimeMillis());
	Population population = null;

	@Override
	public Organism selectOrganism(Population population)
	{
		if(population == null) 
		{
			return null;
		}
		
		this.population = population;
		int runningTotal = 0;

		if(getSumOfPopulationFitnesses() != 0)
		{

			int randomSelectPoint = getRandomSelectPoint();
			//count up until randomSelectPoint is reached, and take the organism at that point
			//this allows organisms with higher fitness to have a better chance of being selected
			for(Organism organism : population.getPopulation())
			{
				SimpleStringOrganism currentOrganism = (SimpleStringOrganism)organism;
				runningTotal += currentOrganism.calculateFitness()*currentOrganism.getNumberOfGenes();
				if(runningTotal >= randomSelectPoint)
				{
					return currentOrganism;
				}
			}
		}
		else
		{
			int randomIndex = Math.abs(randomGenerator.nextInt())%population.getPopulationSize();
			SimpleStringOrganism randomZeroFitnessOrganism = (SimpleStringOrganism) ((StaticSizePopulation)population).getOrganismAtIndex(randomIndex);
			return randomZeroFitnessOrganism;
		}
	
		return null;
	}
	
	private int getRandomSelectPoint()
	{
		int randomInt = Math.abs(randomGenerator.nextInt());
		return randomInt%(getSumOfPopulationFitnesses()+1);//add one to avoid division by zero
	}
	
	private int getSumOfPopulationFitnesses()
	{
		int sum = 0;
		for(Organism organism : population.getPopulation())
		{
			SimpleStringOrganism currentOrganism = (SimpleStringOrganism)organism;
			sum += getOrganismWeight(currentOrganism);	
		}
		return sum;	
	}
	
	private int getOrganismWeight(SimpleStringOrganism o)
	{
		float fitness = o.calculateFitness();
		int intFitness = (int)(fitness*o.getNumberOfGenes());
		return intFitness;
	}

}
